/**
 * @file drv_ws2812.c
 * @author Blues Jiang
 * @brief
 * @version 0.1
 * @date 2022-03-24
 *
 * @copyright Copyright (c) 2022
 *
 */

#include <drv_ws2812.h>
#include <rtthread.h>

ws2812_dev_t ws2812_create(char *spi_name, uint16_t led_node_length)
{
    if (!spi_name || !led_node_length)
    {
        return RT_NULL;
    }

    struct rt_spi_device *spi = (struct rt_spi_device *)rt_device_find(spi_name);

    if (spi == RT_NULL)
    {
        return RT_NULL;
    }
    

    ws2812_dev_t ws2812 = (ws2812_dev_t)rt_malloc(sizeof(struct ws2812_dev));
    ws2812->buff = (uint8_t *)rt_malloc(OneNodeBuffLength * led_node_length);

    if (!ws2812->buff)
    {
        rt_kprintf("There is not enough memory to create a buffer.\r\n");
        rt_free(ws2812);
        return RT_NULL;
    }

    //  配置 spi
    struct rt_spi_configuration ws2812_spi_config;
    ws2812_spi_config.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB; //  高位在前
    ws2812_spi_config.max_hz = WS2812_MAX_FREQ;
    ws2812_spi_config.data_width = 8;
    rt_spi_configure((struct rt_spi_device *)spi, &ws2812_spi_config);
    //  赋值
    ws2812->spi = spi;
    ws2812->node_len = led_node_length;
    return ws2812;
}

void ws2812_clear_buff(ws2812_dev_t ws2812)
{
    if (!ws2812 || !ws2812->buff || !ws2812->node_len)
    { return; }

    rt_memset(ws2812->buff, 0x00, OneNodeBuffLength * ws2812->node_len);
}

//  写颜色节点颜色到缓冲区  //  2byte == 1bit
void ws2812_write_buff(uint8_t *buff, uint8_t r, uint8_t g, uint8_t b)
{
    #if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB)
    rt_uint32_t color = g << 16 | r << 8 | b;
    #elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_RGB)
    rt_uint32_t color = r << 16 | g <<  8 | b;
    #elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_BGR)
    rt_uint32_t color = b << 16 | g <<  8 | r;
    #endif
    rt_uint8_t i = 24;
    rt_uint32_t temp = 0x00000000;

    while (i--)
    {
        //bit1 of 4:
        if (color & 0x00800000)
        {
            temp = (temp << OneBitOccupySPIBit) + (SPIBit_value1 & SPIBitValid);
        }
        else
        {
            temp = (temp << OneBitOccupySPIBit) + (SPIBit_value0 & SPIBitValid);
        }

        color <<= 1;

        if (i % BitsNumWhenSPIBitIsDivisible == 0)
        {
            *buff++ = (temp >> 16) & 0xff;
            *buff++ = (temp >> 8) & 0xff;
            *buff++ = temp & 0xff;
            temp = 0x00000000;
        }
    }
}

void ws2812_write_rgb_to_node(ws2812_dev_t ws2812, uint16_t index, uint8_t r, uint8_t g, uint8_t b)
{
    ws2812_write_buff(&ws2812->buff[OneNodeBuffLength * index], r, g, b);
}

void ws2812_write_rgb_to_all(ws2812_dev_t ws2812, uint8_t r, uint8_t g, uint8_t b)
{
    uint16_t i;

    for (i = 0; i < ws2812->node_len; i++)
    {
        ws2812_write_rgb_to_node(ws2812, i, r, g, b);
    }
}

void ws2812_write_rgb_to_all_24bit(ws2812_dev_t ws2812, uint32_t rgb)
{
    uint16_t i;

    for (i = 0; i < ws2812->node_len; i++)
    {
        ws2812_write_rgb_to_node(ws2812, i, ((rgb>>16)&0xFF), ((rgb>>8)&0xFF), (rgb&0xFF));
    }
}

void ws2812_send(ws2812_dev_t ws2812)
{
    if (!ws2812 || !ws2812->spi || !ws2812->buff)
    {
        rt_kprintf("Parame is null\r\n");
        return;
    }

    rt_spi_send(ws2812->spi, ws2812->buff, OneNodeBuffLength * ws2812->node_len);
}
